/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package helloscala.practise.chapter9

import helloscala.practise.ChapterEntry
import scala.actors.Actor
import scala.actors.Actor._

object Chapter9Entry extends ChapterEntry {
  def runTests: Unit = {
    testSleepingBarberProb
  }

  def testSleepingBarberProb = {
    BarberShopSimulator.startSimulate
  }

  def testMailBox = {
    val actor1 = actor {
      loop {
        react {
          case "how many" => println("You've got " + mailboxSize + " messages.")
          case "exit" => println("exit!"); exit
        }
      }
    }

    // without Thead.sleep(), console might not be printed in the expected sequence,
    // seems latest version scala separate case process code and mailbox queue update
    // into different threads.
    //
    // according to above prob, latest principle should be as follow:
    // 1. put message into mailbox(queue)
    // 2. mailboxSize += 1
    // 3. try matching, if match found, start another thread to process message and remove it from the queue
    //
    actor1 ! 1
    actor1 ! 1
    actor1 ! 1
    actor1 ! "how many"
    Thread.sleep(50)
    actor1 ! "how many"
    actor1 ! 1
    Thread.sleep(50)
    actor1 ! "how many"
    actor1 ! "exit"

    actor1 ! 1 //nothing happen cos actor1 already exit
    actor1 ! "how many"
  }

  def testTypicalMessagingActor = {
    //similar to ShapeDrawingActor in chapter1
    class Actor1 extends Actor {
      def act = {
        loop { //just a shortcut of while(true)
          receive { //block current thread until a message received
            case i: Int => println("An integer received: " + i)
            case s: String => println("A text received: " + s)
            case _ => println("Unknown message"); exit
          }
        }
      }
    }

    val actor1 = new Actor1
    actor1.start
    actor1 ! 30
    actor1 ! "Jeff~!"
    actor1 ! 3.442
  }
  /**
   * Noted that actor2 printed text displayed BEFORE actor1 printed text,
   * because factory-made actor will be started at once on instantiating
   * completed
   */
  def testCreateActor = {
    //manual-made
    class Actor1 extends Actor {
      def act = {
        println("A lot of what acting is, is paying attention.")
      }
    }
    val actor1 = new Actor1
    actor1.start

    //factory-made
    val actor2 = actor { //like static factory method
      println("To be an actor, you have to be a child.")
    }
  }
}
